<?php

if (!function_exists('curl_init')) {
      throw new Exception('Missing CURL PHP extension.');
}
if (!function_exists('json_decode')) {
      throw new Exception('Missing the JSON PHP extension.');
}

class HttpApi {

    /**
     * Version.
     */
    const VERSION = '1';

    /**
     *  Default options for curl.
     */
    public static $CURL_OPTS = array(
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 60,
        CURLOPT_USERAGENT      => 'draco-php-1.0',
    );

    /**
     * Indicates if the CURL based @ syntax for file uploads is enabled.
     */
    protected $fileUploadSupport = false;

    /**
     * Set the file upload support status.
     *
     * @param String $domain the base domain
     */
    public function setFileUploadSupport($fileUploadSupport) {
        $this->fileUploadSupport = $fileUploadSupport;
        return $this;
    }

    /**
     * Get the file upload support status.
     *
     * @return String the base domain
     */
    public function useFileUploadSupport() {
        return $this->fileUploadSupport;
    }

    /**
     * Makes an HTTP request. This method can be overriden by subclasses if
     * developers want to do fancier things or use something other than curl to
     * make the request.
     *
     * @param String $url the URL to make the request to
     * @param Array $params the parameters to use for the POST body
     * @param CurlHandler $ch optional initialized curl handle
     * @return String the response text
     */
    public function makeRequest($url, $params, $ch=null) {
        if (!$ch) {
            $ch = curl_init();
        }

        $opts = self::$CURL_OPTS;
        if ($this->useFileUploadSupport()) {
            $opts[CURLOPT_POSTFIELDS] = $params;
        } else {
            $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
        }
        $opts[CURLOPT_URL] = $url;

        // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
        // for 2 seconds if the server does not support this header.
        if (isset($opts[CURLOPT_HTTPHEADER])) {
            $existing_headers = $opts[CURLOPT_HTTPHEADER];
            $existing_headers[] = 'Expect:';
            $opts[CURLOPT_HTTPHEADER] = $existing_headers;
        } else {
            $opts[CURLOPT_HTTPHEADER] = array('Expect:');
        }

        curl_setopt_array($ch, $opts);
        $result = curl_exec($ch);

        // what will be use in OAuth2
        if (curl_errno($ch) == 60) {  //CURLE_SSL_CACERT
            self::errorLog('Invalid or no certificate authority found, using bundled information');
            curl_setopt($ch, CURLOPT_CAINFO,
                dirname(__FILE__) . '/ty_ca_chain_bundle.crt');
            $result = curl_exec($ch);
        }
		/*
        if ($result === false) {
            $error_msg = array(
                    'error_code' => curl_errno($ch),
                    'error'      => array(
                        'message'    => curl_error($ch),
                        'type'       => 'CurlException',
                    ),
            );
            print_r($url);
            print_r($error_msg);
        }
        */
        curl_close($ch);
        return $result;
    }

     /**
     * support function for tybbs xml parser
     *
     * @param Array $array the result array
     * @param Array $stack the array stack for temp result
     * @param String $value current value needs to be set
     */
    protected function setarrayvalue(&$array, $stack, $value) 
    {
        if ($stack) 
        {
            $key = array_shift($stack);
            $this->setarrayvalue($array[$key], $stack, $value);
            return $array;
        } 
        else 
        {
            $array = $value;
        }//if-else
    }//function setArrayValue

   /**
     *
     *    An easy lightweight (Array ->) XML -> Array algorithm for TianYa BBS article interface.
     *    
     *    @param String $xml the result xml from TianYa bbs interface
     *    @return Array the output array from xml
     *
     */
    public function tybbs_xmltoarray($xml) 
    {
        $parser = xml_parser_create('UTF-8'); // For Latin-1 charset
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); // Dont mess with my cAsE sEtTings
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); // Dont bother with empty info
        xml_parse_into_struct($parser, $xml, $values);
        xml_parser_free($parser);
        //    print_r($values);

        $single_result = array();
        $return = array(); // The returned array
        $stack = array(); // tmp array used for stacking
        foreach($values as $val) 
        {
            if($val['type'] == "open") 
            {
                array_push($stack, $val['tag']);
            } 
            elseif($val['type'] == "close") 
            {
                array_pop($stack);
                if ($val['tag'] == 'row')
                {
                    $return[] = $single_result['dataset']['row'];
                }

            }
            elseif($val['type'] == "complete") 
            {
                array_push($stack, $val['tag']);
                $this->setarrayvalue($single_result, $stack, $val['value']);
                array_pop($stack);
            }//if-elseif
        }//foreach
        return $return;
    }//function XMLToArray
    
    /**
     * help function for sort bbs data by time
     * @param Array $left one bbs data array
     * @param Array $right one bbs data array
     * @return 1 if $left time is early than $right
     */
    static public function bbs_sort($left, $right)
    {
        $left_time = strtotime($left['compose_time']);
        $right_time = strtotime($right['compose_time']);

        return ($left_time < $right_time) ? 1 : -1;
    }

    public function getVerifier($verify_string)
    {
        return substr(md5($verify_string), 0, 8);
    }
}
?>
